Software programming has changed over the years as computer programs have moved away from a sequential model of performing operations and toward a more asynchronous model wherein multiple operations of a single program may be performed substantially simultaneously. These computer programs are typically referred to as “event-driven” programs in that a user may initiate an event in the program and thereafter fail to take any other action with respect to that event for an indefinite period of time. As such, the program is in a waiting pattern in which the program takes no action with respect to this event until the user initiates such. During this interim, the user may initiate any number of other events in the computer program, take any number of other actions with respect to these other events, or perform no action during this interim.
Event-driven programs may perform any number of internal operations while waiting for the user to take action with respect to the initiated event or while the user is currently taking action with respect to that or any other event. That is, these programs do not execute tasks and perform operations in a sequential manner, but rather, in a concurrent manner wherein tasks and operations are performed substantially simultaneously with respect to each other. For instance, in a word processor having a graphical user interface, a user may select a control for formatting text in a document using a word processor application program. Meanwhile, between selection of the control and action by the user in the document utilizing the formatting function activated by the control, an auto save feature of the processor may be activated by an internal call initiated by the word processor application. The auto save and formatting operations thus execute logically in a concurrent manner, i.e., “concurrently,” with each other in the word processor.
The increasing use of distributed computing environments further illustrates the aforementioned transition in software programming. In distributed computing environments, multiple computer programs communicate with one another by passing messages over channels through which the programs are operably connected using some form of network connection, such as a Local Area Network, Wide Area Network, the Internet, or the like. A distributed computing environment may contain various application programs running on multiple computing systems. These application programs are operable to communicate with any number of application programs connected over the same network or possibly another network connection. Application programs, or instances thereof, in a distributed computing environment often await communications from other application programs. During this indefinite wait period, an application program may continue to perform operations, such as communicating with other application programs by sending and/or receiving messages. Consequently, application programs operating in a distributed computing environment perform tasks and operations in a concurrent manner that is similar to the event-driven application programs described above.
Collectively, application programs operating in a distributed computing environment and event-driven application programs may be referred to as “concurrent,” or “message-passing” applications. Although message-passing applications provide many functional advantages over sequential application programs, message-passing applications are not without problems. One common problem associated with message-passing application programs is deadlock. Deadlock is an error that may occur in many situations, but most frequently, in situations where an expected action for an operation never occurs. For instance, deadlock may occur when a message sent by a sender (caller) is never received by a receiver (callee). Likewise, deadlock may occur when a receiver waits for a message that is never actually sent by a sender.
Together with deadlock errors, asynchrony and nondeterminism introduced by the unpredictable nature of when message-passing applications may render a specific action make message-passing applications more difficult to write, debug, test and tune than applications operating in a sequential manner. Today's programming languages and tools currently offer little or no support for concurrent programming. Indeed, known methods for evaluating, or checking, behavioral properties of a message-passing application program are extremely difficult and time-consuming. Moreover, there are no current modeling techniques that accurately address the problems of detecting deadlock errors.
In hardware and protocol design, there has been relative success in modeling different agents as communicating finite state machines and thereafter using model checking to explore the interactions, i.e., behavioral properties, between the agents. As such, a model is defined for the processes of the hardware as a whole. Similar agents in concurrent software, which are commonly referred to as asynchronous functions, or operations, tend to have more complicated communication structure than agents in hardware. Indirect references and dynamic creation of new objects and functions play a prominent role in the interaction between software agents. For instance, one operation can create a new object and send a reference for the object to a second operation. Following this, both operations can read or change the contents of the object. Such interactions are typically difficult to model using communicating finite state machines. In addition, a fundamental obstacle in checking behavioral properties, such as deadlock freedom and communication progress, between software agents is the exponential state space explosion resulting in model checking.